from typing import List, Optional, Union
import win32gui
import win32con
import win32api
import time
import threading
from .mouse.mouse_manager import MouseManager
from .keyboard.keyboard_manage import KeyboardManager
from utils.window.window_tools import WindowTools
from utils import log_message

class PhysicalControlManager:
    """物理控制管理器 - 监听主窗口操作并同步到其他窗口"""
    
    def __init__(self):
        self.mouse = MouseManager()
        self.keyboard = KeyboardManager()
        self.window_manager = WindowTools()
        self.main_hwnd: Optional[int] = None
        self.sub_hwnds: List[int] = []
        self.is_monitoring = False
        self.monitor_thread = None
        
    def set_main_window(self, hwnd: Optional[int] = None) -> bool:
        """设置主窗口，如果未指定则使用当前激活窗口"""
        try:
            if hwnd is None:
                # 获取当前激活窗口
                active_hwnd = win32gui.GetForegroundWindow()
                # 检查是否为游戏窗口
                if win32gui.GetClassName(active_hwnd) == self.window_manager.GAME_CLASS_NAME:
                    self.main_hwnd = active_hwnd
                else:
                    return False
            else:
                if win32gui.IsWindow(hwnd):
                    self.main_hwnd = hwnd
                else:
                    return False
            
            self._update_sub_windows()
            return True
        except Exception as e:
            log_message(f"设置主窗口失败: {e}", "error")
            return False
    
    def _update_sub_windows(self):
        """更新从窗口列表"""
        try:
            # 获取所有窗口（不改变位置）
            all_windows = self.window_manager.get_window()
            # 过滤出除主窗口外的所有可见窗口
            self.sub_hwnds = [window.hwnd for window in all_windows 
                            if window.hwnd != self.main_hwnd 
                            and window.is_visible 
                            and not window.is_minimized]
            return True
        except Exception as e:
            log_message(f"更新从窗口失败: {e}", "error")
            return False

    def _get_relative_position(self, x: int, y: int, target_hwnd: int) -> tuple:
        """计算相对位置，使用窗口客户区坐标"""
        try:
            # 获取主窗口客户区
            main_rect = win32gui.GetWindowRect(self.main_hwnd)
            main_point = win32gui.ScreenToClient(self.main_hwnd, (x, y))
            
            # 如果点击位置在窗口外，返回原始坐标
            if main_point[0] < 0 or main_point[1] < 0:
                return x, y
                
            # 获取目标窗口客户区
            target_point = win32gui.ClientToScreen(target_hwnd, main_point)
            return target_point
            
        except Exception as e:
            log_message(f"计算相对位置失败: {e}", "error")
            return x, y

    def _monitor_keyboard(self):
        """监控所有键盘输入"""
        try:
            # 记录所有按键状态
            key_states = {}
            
            while self.is_monitoring:
                # 检查是否有游戏窗口被激活
                active_hwnd = win32gui.GetForegroundWindow()
                if win32gui.GetClassName(active_hwnd) == self.window_manager.GAME_CLASS_NAME:
                    self.main_hwnd = active_hwnd
                    self._update_sub_windows()
                    
                    # 检查所有可能的按键
                    for vk in range(0x01, 0xFE):  # 检查所有可能的虚拟键码
                        key_state = win32api.GetAsyncKeyState(vk)
                        
                        # 按键按下
                        if key_state & 0x8000:
                            if not key_states.get(vk, False):
                                key_states[vk] = True
                                for hwnd in self.sub_hwnds:
                                    # 发送按键按下消息
                                    scan_code = win32api.MapVirtualKey(vk, 0)
                                    lparam = (scan_code << 16) | 1
                                    win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, vk, lparam)
                                    # 对于可打印字符，发送WM_CHAR消息
                                    if 0x20 <= vk <= 0x7E:
                                        win32api.PostMessage(hwnd, win32con.WM_CHAR, vk, lparam)
                        
                        # 按键释放
                        elif key_states.get(vk, False):
                            key_states[vk] = False
                            for hwnd in self.sub_hwnds:
                                scan_code = win32api.MapVirtualKey(vk, 0)
                                lparam = (scan_code << 16) | 0xC0000001
                                win32api.PostMessage(hwnd, win32con.WM_KEYUP, vk, lparam)
                                
                time.sleep(0.01)
        except Exception as e:
            log_message(f"键盘监控错误: {e}", "error")

    def _monitor_mouse(self):
        """监控鼠标操作"""
        try:
            mouse_state = {'left': False, 'right': False, 'middle': False}
            last_pos = (0, 0)
            
            # 定义鼠标消息映射
            MOUSE_MESSAGES = {
                'left': (win32con.WM_LBUTTONDOWN, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON),
                'right': (win32con.WM_RBUTTONDOWN, win32con.WM_RBUTTONUP, win32con.MK_RBUTTON),
                'middle': (win32con.WM_MBUTTONDOWN, win32con.WM_MBUTTONUP, win32con.MK_MBUTTON)
            }
            
            while self.is_monitoring:
                active_hwnd = win32gui.GetForegroundWindow()
                if win32gui.GetClassName(active_hwnd) == self.window_manager.GAME_CLASS_NAME:
                    self.main_hwnd = active_hwnd
                    self._update_sub_windows()
                    
                    # 获取鼠标位置
                    current_pos = win32gui.GetCursorPos()
                    
                    # 如果鼠标移动，同步移动
                    if current_pos != last_pos:
                        for hwnd in self.sub_hwnds:
                            target_x, target_y = self._get_relative_position(*current_pos, hwnd)
                            lparam = self.mouse._make_lparam(target_x, target_y)
                            win32api.PostMessage(hwnd, win32con.WM_MOUSEMOVE, 0, lparam)
                        last_pos = current_pos
                    
                    # 检查鼠标按键
                    for button, vk in [('left', win32con.VK_LBUTTON), 
                                     ('right', win32con.VK_RBUTTON),
                                     ('middle', win32con.VK_MBUTTON)]:
                        state = win32api.GetAsyncKeyState(vk)
                        down_msg, up_msg, wparam = MOUSE_MESSAGES[button]
                        
                        if state & 0x8000:
                            if not mouse_state[button]:
                                mouse_state[button] = True
                                for hwnd in self.sub_hwnds:
                                    target_x, target_y = self._get_relative_position(*current_pos, hwnd)
                                    lparam = self.mouse._make_lparam(target_x, target_y)
                                    win32api.PostMessage(hwnd, down_msg, wparam, lparam)
                            elif mouse_state[button]:
                                mouse_state[button] = False
                                for hwnd in self.sub_hwnds:
                                    target_x, target_y = self._get_relative_position(*current_pos, hwnd)
                                    lparam = self.mouse._make_lparam(target_x, target_y)
                                    win32api.PostMessage(hwnd, up_msg, 0, lparam)
                                
                time.sleep(0.01)
        except Exception as e:
            log_message(f"鼠标监控错误: {e}", "error")

    def start_monitoring(self, monitor_type: str = 'all'):
        """
        开始监控
        monitor_type: 'keyboard', 'mouse', 'all'
        """
        self.is_monitoring = True
        
        if monitor_type in ['keyboard', 'all']:
            keyboard_thread = threading.Thread(target=self._monitor_keyboard)
            keyboard_thread.daemon = True
            keyboard_thread.start()
            
        if monitor_type in ['mouse', 'all']:
            mouse_thread = threading.Thread(target=self._monitor_mouse)
            mouse_thread.daemon = True
            mouse_thread.start()

    def stop_monitoring(self):
        """停止监控"""
        self.is_monitoring = False